<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"> <meta name="viewport" content="width=device-width">
    <title>用fft画画</title>
    <meta name="viewport" content="width=device-width,initial-scale=1, shrink-to-fit=no">
    <!-- Bootstrap CSS -->
    <link rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css"
          integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
          crossorigin="anonymous">
    <link rel="stylesheet"
          href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/androidstudio.min.css">
<!--    <link rel="stylesheet" href="/web_template_css.css">-->
    <!-- this is highlight.js -->
    <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
    <script id="MathJax-script" async
            src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js">
    </script>
    <script  src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
    integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
    integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js"
    integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
    <style>
      img{
        display: block;
        height: auto;
        max-width: 100%;
      }
    </style>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">kvrmnks</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
          <ul class="navbar-nav">
            <li class="nav-item active">
              <a class="nav-link" href="./../../../../../index.html" target="_self">Home <span class="sr-only">(current)</span></a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./../../../../../blog.html">Blog</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="./../../../../../about.html">About</a>
            </li>
          </ul>
        </div>
      </nav>



    <div class='container'>
      <p>外面疫情严重,只能赋闲在家,闲着也是闲着,来学用fft画画吧</p>

<p><img src="1587643407396.jpg" alt=""></p>

<!--more-->

<p><del>顺便预习一下马上要学的QT</del></p>

<h3><strong>fft</strong></h3>

<p>既然要用fft画画当然要会fft的呀,什么你还不会fft?</p>

<p><img src="1587643414466.png" alt=""></p>

<p>如果你不会请去自己学  <del>其实有板子在会不会有什么区别呢</del>  </p>

<p>这里丢个一直在用的fft板子  </p>

<p>复数类板子<br>
``` cpp</p>

<p>class Complex{</p>

<p>private:</p>

<pre><code>qreal a,b;
</code></pre>

<p>public:</p>

<pre><code>Complex(qreal a=0,qreal b=0):a(a),b(b){}

Complex operator * (qreal x)const;

Complex operator * (const Complex &amp;y)const;

Complex operator + (const Complex &amp;y)const;

Complex operator - (const Complex &amp;y)const;

qreal length()const{

    return sqrt(a*a+b*b);

}

qreal real()const{return a;}

qreal img()const{return b;}
</code></pre>

<p>};</p>

<p>Complex operator * (qreal x,Complex y);</p>

<p>Complex Complex::operator*(qreal x) const{</p>

<pre><code>return Complex(this-&gt;a*x,this-&gt;b*x);
</code></pre>

<p>}</p>

<p>Complex Complex::operator*(const Complex &amp;y) const{</p>

<pre><code>Complex ret(this-&gt;a*y.a-this-&gt;b*y.b,this-&gt;a*y.b+this-&gt;b*y.a);

return ret;
</code></pre>

<p>}</p>

<p>Complex Complex::operator+(const Complex &amp;y) const{</p>

<pre><code>return Complex(this-&gt;a+y.a,this-&gt;b+y.b);
</code></pre>

<p>}</p>

<p>Complex Complex::operator-(const Complex &amp;y) const{</p>

<pre><code>return Complex(this-&gt;a-y.a,this-&gt;b-y.b);
</code></pre>

<p>}</p>

<p>Complex operator * (qreal x,Complex y){</p>

<pre><code>return y*x;
</code></pre>

<p>}</p>

<pre><code>
fft板子  

``` cpp

void fft(QVector&lt;Complex&gt;&amp;data,int n){

    QVector&lt;int&gt; rev(n);

    int R = 0;

    while((1&lt;&lt;(R+1))&lt;=n)R++;

    for(int i=0;i&lt;n;i++)rev[i]=(rev[i&gt;&gt;1]&gt;&gt;1)|((i&amp;1)&lt;&lt;(R-1));

    for(int i=0;i&lt;n;i++){

        if(i&lt;rev[i])

            std::swap(data[i],data[rev[i]]);

    }

    qreal pi = acos(-1);

    for(int i=1;i&lt;n;i&lt;&lt;=1){

        Complex w(cos(pi/i),sin(pi/i));

        for(int j=0;j&lt;n;j+=(i&lt;&lt;1)){

            Complex wn(1,0);

            for(int k=0;k&lt;i;k++){

                Complex x=data[j+k],y=wn*data[j+i+k];

                data[j+k]=x+y;

                data[i+j+k]=x-y;

                wn=wn*w;

            }

        }

    }

}

</code></pre>

<p>这里顺便说下绘图的原理,像是在做函数曲线一样,要描点连线  </p>

<p>也就是要求一开始要给我一个点列\(A[i]=(x_i,y_i)\)  </p>

<p>为了让它fft,需要把这个点列转化到复平面上\(A[i]=x_i+y_i*i\)  </p>

<p>顺便记点数为\(n\)</p>

<p>然后就可以fft了呢  </p>

<p>假设生成的数列为\(B[i]\)   </p>

<p>那我们明显有</p>

<p>\[A[j]=\frac{1}{n}*\sum_{k=0}^{k&lt;n}B[k]*e^{\frac{2\pi ji}{n}*k}\]</p>

<p>因为每一项都是复数,所以我们可以把它对应到复平面上,这样\(A[j]\)就变成了一系列向量的和,有了明显的几何意义  </p>

<h3><strong>QT</strong></h3>

<h5><strong>安装</strong></h5>

<p>请去清华镜像站下载安装包</p>

<h5><strong>用QT绘画</strong></h5>

<p>好像有两种办法来着  </p>

<p>1.QPainter  </p>

<p>2.QGraphics  </p>

<p>第一种跟java swing那套理论差不多要自己重写绘图事件,鉴于之前就被swing恶心到了,而且这种方式一点都不OOP于是选了第二种  </p>

<p>第二种就是</p>

<p>一些基本的图形由QGraphicsItem继承得到  </p>

<p>要把这些图形丢到QGraphicsScene里,让它来做排版  </p>

<p>然后把QGraphicsScene丢给QGraphicsView让它显示出来就好了呢!  </p>

<p>具体的代码在下一节  </p>

<h5><strong>signal and slot</strong></h5>

<p>这个是Qt里新的逻辑呢</p>

<p>简单的用法是</p>

<pre><code class="language-cpp">
QObject::connect(发出信号的对象地址,SIGNAL(信号函数),接受信号的对象地址,SLOT(槽函数));

</code></pre>

<p>一旦这样做了之后呢</p>

<p>发出信号的函数一旦发出了信号,接受信号的对象就会立即执行槽函数  </p>

<p>跟javafx里的property机制很像呢  </p>

<p>举个具体的例子吧  </p>

<pre><code class="language-cpp">
    QApplication a(argc, argv);

    QGraphicsScene *scene = new QGraphicsScene(0,0,1024,768);

    QGraphicsView *view = new GraphicsView(scene);

    QPushButton *button = new QPushButton(&quot;exit&quot;);

    QObject::connect(button,SIGNAL(clicked()),&amp;a,SLOT(exit()));

    view-&gt;addWidget(button);

    view-&gt;show();

</code></pre>

<p>这样如果按钮被点击了,窗口就会被关闭了  </p>

<h5><strong>QTimeLine</strong></h5>

<p>毕竟要做出来的是个动画  </p>

<p>当然要学学时间轴啦 <del>其实不会也没事呢</del>  </p>

<p>下面是代码节选  </p>

<pre><code class="language-cpp">
QTimeLine *time = new QTimeLine(40000);

time-&gt;setFrameRange(0,1024);

QObject::connect(time,SIGNAL(frameChanged(int)),scene,SLOT(next()));

time-&gt;start();

</code></pre>

<p>第一个构造函数里面的参数是时间轴持续的时间,单位毫秒  </p>

<p>setFrameRange(int,int)  </p>

<p>第一个参数表示每帧耗时多少毫秒 如果填0的话默认每帧40毫秒  </p>

<p>第二个参数表示一共有多少帧  </p>

<p>注意如果进行着时间超出了一开始构造函数的时间,就停了,当然如果时间到了还没进行完,也会停  </p>

<p>那个next()是我定义的函数,作用是描下一个点  </p>

<p>到现在为止就已经可以完成整个动画了呢  </p>

<p><img src="1587643425697.jpg" alt=""></p>

<h3><strong>Qt打包</strong></h3>

<p>当你做好了程序想要给小伙伴展示的时候怎么可能简简单单地丢给他们代码呢?  </p>

<p>qt打包的方法网上到处都是,我们来说说我犯过的坑吧  </p>

<p>##### <strong>提示无法定位到Q5Gui.dll类</strong></p>

<p>可能你的打包程序出了锅,你可以尝试ProcessExplorer然后把程序调用的dll自己挑过去</p>

<h5><strong>0x000000007b 大约长这样子~</strong></h5>

<p>当你好不容易找全了dll,却发现了这么个错这是为啥呢  </p>

<p><img src="1587643431546.jpg" alt=""></p>

<p>经过我漫长的调试,发现原因是我在qtcreator里编译是用的qt自带的gcc  </p>

<p>但是打包时我用的是dev里的cpp  </p>

<p>因为我原来在用gcc的时候把dev的gcc在环境变量里优先度提得太高了</p>

<p>于是打包的时候gcc自动用了dev的,导致版本不一致  </p>

<p>于是在环境变量设置里把qt的gcc优先度调到最高就好了呢  </p>

<p><img src="1587643436909.gif" alt=""></p>

<h3><strong>项目代码</strong></h3>

<p>我放到github上了  </p>

<p><a href="https://github.com/kvrmnks/FFt-drawing">链接</a></p>


    </div>
    <script>
      hljs.initHighlightingOnLoad()
    </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.5.0/highlightjs-line-numbers.min.js"></script>
  <script>
      hljs.initHighlightingOnLoad();
      hljs.initLineNumbersOnLoad();
  </script>
  </body>
</html>